<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Observer Pattern</title>
<!-- Attach necessary scripts -->
<script type="text/javascript" src="../jquery-1.8.2.min.js"></script>

</head>
<body>

<div class="display"></div>

<script type="text/javascript">
/* ------------
 * # Subject
 * ------------ */
var ISubject = function() {};
ISubject.prototype = {
	regist: function(){
		throw new Error("Observer#regist needs to be overridden.");
	},
	unregist: function(){
		throw new Error("Observer#unregist needs to be overridden.");
	}
};

var Subject = function(){
    this.observers = [];	
};
Subject.prototype = Object.create(ISubject.prototype);
Subject.prototype.registerObserver = function(o) {
	this.observers = this.observers.concat(o); 
};
Subject.prototype.unregisterObserver = function(o) {
	   var ob = this.observers;
	   var idx = 0;
	   
	   for ( var i=0, max=ob.length ; i<max ; i++ ) {
		   if ( ob[i] === o) {
			   this.observers = ob.slice(0, i).concat( ob.slice(i+1, ob.length))
			   return ;
		   }
	   }
};
Subject.prototype.notify = function(){
	console.log('this.observers', this.observers);
	var ob = this.observers;
	for( var i in ob ) {
		if ( ob.hasOwnProperty(i) ) {
			ob[i].update();
		}
	}
	
};
	
var subject = new Subject();

/* ------------
 * # Observer
 * ------------ */
var IObserver = function() {};
IObserver.prototype.update = function() {
    throw new Error("Observer#update needs to be overridden.");
}

var Observer = function(name, control) {
	this.name = name;
	this.control = control;
};
Observer.prototype = Object.create(IObserver.prototype);
Observer.prototype.update = function() {
	this.control.append('<p>My name is ' + this.name + '</p>');
}

var control = $('.display');

control.append('<p><h1>Basic</h1></p>');

control.append('<p style="color:red;">> add Observer <b>[First, Second, Third]</b> to Subject</p>');
var ob1 = new Observer('First observer', control);
var ob2 = new Observer('Second observer', control);
var ob3 = new Observer('Third observer', control);

subject.registerObserver([ob1, ob2, ob3]);

subject.notify();
control.append('<p style="color:red;">> remove Second Observer</p>');
subject.unregisterObserver(ob2);
subject.notify();
control.append('<p style="color:red;">> remove First Observer</p>');
subject.unregisterObserver(ob1);
subject.notify();

control.append('<hr />');
control.append('<hr />');
control.append('<p><h1>Keep subject reference</h1></p>');

// #
var Observer2 = function(subject, control, name) {
	this.subject = subject;
	this.control  = control;
	this.name    = name;
	
	this.subject.registerObserver(this);
};
Observer2.prototype = Object.create(IObserver.prototype);
Observer2.prototype.update = function() {
    this.control.append('<p>My name is ' + this.name + '</p>');
};
Observer2.prototype.unregister = function() {
	this.subject.unregisterObserver(this);
};
var subject2 = new Subject();
var ob2_1 = new Observer2(subject2, control, 'First observer');
var ob2_2 = new Observer2(subject2, control, 'Second observer');
var ob2_3 = new Observer2(subject2, control, 'Third observer');
subject2.notify();

control.append('<p style="color:red;">> unregister Second observer</p>');
ob2_2.unregister();
subject2.notify();
</script>
</body>
</html>